﻿/**************************************************************
 *
 * 唯一标识：c5f956f8-4e71-41a6-878b-20bc63dde8d7
 * 命名空间：Sgr.Threading
 * 创建时间：2024/6/20 16:46:26
 * 创建者：CocoYuan
 * 描述：对 long 提供无锁原子操作。算术为 unchecked 环绕。
 *
 **************************************************************/

using System.Runtime.CompilerServices;

namespace Sgr.Threading
{
    /// <summary>
    /// 提供对 <c>long</c> 的原子读/写/增减等操作。
    /// 所有访问经 <see cref="Interlocked"/>，保证：
    /// 1. 原子性（包括在 32 位平台上对 64 位值的读）；
    /// 2. 必要的内存可见性（读写具 release/acquire 语义）。
    ///
    /// 溢出说明：加减与增减采用 unchecked 环绕（2^64 模），不抛出异常。
    /// 注意：<c>Increment</c>/<c>PreIncrement</c> 与 <c>Decrement</c>/<c>PreDecrement</c> 返回值语义不同（旧值 vs 新值），请按注释使用。
    /// </summary>
    public sealed class AtomicLong
    {
        private long _value;

        /// <summary>
        /// 创建一个初始值为 <c>0</c> 的新 <c>AtomicLong</c> 实例。
        /// </summary>
        public AtomicLong()
            : this(0)
        {
        }

        /// <summary>
        /// 创建一个具有提供的初始值的新 <c>AtomicLong</c> 实例。
        /// </summary>
        public AtomicLong(long value)
        {
            _value = value;
        }

        /// <summary>
        /// 返回当前值。
        /// </summary>
        /// <returns>
        /// 以原子方式访问的 <c>long</c> 值。
        /// </returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long Get() => Interlocked.Read(ref _value);

        /// <summary>
        /// 以原子方式设置当前值。
        /// </summary>
        /// <param name="value">
        /// 要设置的新值。
        /// </param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Set(long value) => Interlocked.Exchange(ref _value, value);

        /// <summary>
        /// 以原子方式设置值并返回原始值。
        /// </summary>
        /// <param name="value">
        /// 新值。
        /// </param>
        /// <returns>
        /// 设置新值之前的值。
        /// </returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long GetAndSet(long value) => Interlocked.Exchange(ref _value, value);

        /// <summary>
        /// 如果当前值 <c>==</c> 预期值，则以原子方式将值设置为给定的更新值。
        /// </summary>
        /// <param name="expected">
        /// 要比较的值。
        /// </param>
        /// <param name="result">
        /// 如果值等于 <c>expected</c> 值，则设置的值。
        /// </param>
        /// <returns>
        /// 如果比较和设置成功，则返回 <c>true</c>。<c>false</c> 表示比较失败。
        /// </returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool CompareAndSet(long expected, long result) =>
            Interlocked.CompareExchange(ref _value, result, expected) == expected;

        /// <summary>
        /// 以原子方式将给定值添加到当前值。
        /// </summary>
        /// <param name="delta">
        /// 要添加的值。
        /// </param>
        /// <returns>
        /// 更新后的值。
        /// </returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long AddAndGet(long delta) => Interlocked.Add(ref _value, delta);

        /// <summary>
        /// 以原子方式将 <c>delta</c> 添加到值并返回原始值。
        /// </summary>
        /// <param name="delta">
        /// 要添加到现有值的值。
        /// </param>
        /// <returns>
        /// 添加 <c>delta</c> 之前的值。
        /// </returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long GetAndAdd(long delta) => Interlocked.Add(ref _value, delta) - delta;

        /// <summary>
        /// 将值增加 1 并返回之前的值。这是后增量的原子版本。
        /// </summary>
        /// <returns>
        /// 增量之前的值。
        /// </returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long Increment() => GetAndAdd(1);

        /// <summary>
        /// 将值减少 1 并返回之前的值。这是后减量的原子版本。
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long Decrement() => GetAndAdd(-1);

        /// <summary>
        /// 将值增加 1 并返回新值。这是前增量的原子版本。
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long PreIncrement() => Interlocked.Increment(ref _value);

        /// <summary>
        /// 将值减少 1 并返回新值。这是前减量的原子版本。
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public long PreDecrement() => Interlocked.Decrement(ref _value);

        /// <summary>
        /// 允许从 <c>AtomicLong</c> 到 <c>long</c> 的隐式转换。
        /// </summary>
        public static implicit operator long(AtomicLong value) => value.Get();
    }
}